package vip.sweet.web.config;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure;
import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.util.Utils;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import jakarta.servlet.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectionException;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import vip.sweet.common.enums.CommonDeleteFlag;

import java.io.IOException;

/**
 * @author ASUS
 * @Date 2025/7/13 17:17
 * @Descripition
 */
@Configuration
@MapperScan("vip.sweet.**.mapper")
public class GlobalConfig implements WebMvcConfigurer {
    /**
     * RedisTemplate配置
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        // 设置objectMapper:转换java对象的时候使用
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // 设置key/value值的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    /**
     * 设置静态资源映射
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //添加静态资源映射规则
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");
        registry.addResourceHandler("doc.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    /**
     * 分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return mybatisPlusInterceptor;
    }

    /**
     * 配置基本信息
     */
    @Bean
    public OpenAPI openAPI() {
        return new OpenAPI().info(new Info()
                //标题
                .title("苗族文化推广系统服务接口")
                //尿素Api接口文档的基本信息
                .description("后端接口服务")
                //版本
                .version("v1.0")
                //设置OpenApi文档的联系信息，姓名，邮箱
                .contact(new Contact().name("sweet").email("sweet@qq.com"))
                //设置OpenAPI文档的许可证信息，包括许可证名称，许可证URL
                .license(new License().name("Apache 2.0").url("https://knife4j.com"))
        );
    }

    /**
     * 自定义公共字段注入
     */
    @Component
    public static class CustomMetaObjectHandler implements MetaObjectHandler {
        /**
         * 删除标志填充
         */
        private static final String IS_DELETED = "isDeleted";
        /**
         * 创建时间填充
         */
        private static final String CREATE_TIME = "createTime";
        /**
         * 更新时间填充
         */
        private static final String UPDATE_TIME = "updateTime";

        @Override
        public void insertFill(MetaObject metaObject) {
            try {
                //为空则设置deleteFlag
                Object isDeleted = metaObject.getValue(IS_DELETED);
                if (ObjectUtil.isEmpty(isDeleted))
                    setFieldValByName(IS_DELETED, EnumUtil.toString(CommonDeleteFlag.NOT_DELETE), metaObject);
            } catch (ReflectionException ignored) {
            }
            try {
                //为空则设置createTime
                Object createTime = metaObject.getValue(CREATE_TIME);
                if (ObjectUtil.isEmpty(createTime)) {
                    setFieldValByName(CREATE_TIME, DateTime.now(), metaObject);
                }
            } catch (ReflectionException ignored) {
            }
        }

        @Override
        public void updateFill(MetaObject metaObject) {
            try {
                //设置updateTime
                setFieldValByName(UPDATE_TIME, DateTime.now(), metaObject);
            } catch (ReflectionException ignored) {
            }
        }
    }

    @Configuration //  配置类
    @ConditionalOnWebApplication //  判断是否是web应用
    @AutoConfigureAfter(DruidDataSourceAutoConfigure.class) //  判断是否引入了DruidDataSourceAutoConfigure
    //  ConditionalOnProperty,参数含义，name：属性名，havingValue：属性值，matchIfMissing：如果havingValue不存在，是否匹配
    @ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true", matchIfMissing = true)
    public static class RemoveDruidAdConfig {
        /**
         * 移除Druid监控页面的广告
         * 方法名称必须为：removeDruidAdFilterRegistrationBean
         * 参数类型必须为：FilterRegistrationBean
         *
         * @param properties DruidStatProperties
         */
        @Bean
        public FilterRegistrationBean<Filter> removeDruidAdFilterRegistrationBean(DruidStatProperties properties) {
            //  获取web监控配置
            DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
            // 获取监控页面的url
            String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
            String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
            final String filePath = "support/http/resources/js/common.js";
            //创建FilterRegistrationBean
            Filter filter = new Filter() {
                @Override
                public void init(FilterConfig filterConfig) throws ServletException {
                }

                @Override
                public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                    filterChain.doFilter(servletRequest, servletResponse);
                    //  移除Druid监控页面的广告
                    servletResponse.resetBuffer();
                    //获取响应输出流
                    String text = Utils.readFromResource(filePath);
                    //正则替换掉js
                    text = text.replaceAll("<a.*?banner\"></a><br/>", "");
                    text = text.replaceAll("powered.*?shrek.wang</a>", "");
                    servletResponse.getWriter().write(text);
                }

                @Override
                public void destroy() {
                }
            };
            FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>(filter);
            registrationBean.setFilter(filter);
            registrationBean.addUrlPatterns(commonJsPattern);
            return registrationBean;
        }
    }
}
